package works;

import cn.pugle.base.uri_encode.EncryptUtil;
import cn.pugle.encrypt.CryptoUtils;
import cn.pugle.encrypt.EncryptorAesGcm;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.config.TinkConfig;
import org.apache.commons.io.IOUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;

import static cn.pugle.encrypt.CryptoUtils.getAESKeyFromPassword;
import static cn.pugle.encrypt.EncryptorAesGcm.*;

/**
 * 艹艹艹艹\0\0\0\0\0\0\0\0\0\0\0\0
 * <p>
 * "Happy 1024! I hide flag into the big thing below.\n" +
 * "And you ask when did I encrypt it? Well, I encrypt it in TODAY.\n" +
 *
 * @author tzp
 * @since 2020/10/23
 */
public class Base64AES {
    static String s = "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";
//    static String s = "HJ/PzA6rXEqJij2YFWjLlw==";

    public static void main(String[] args) throws Exception {
//        test11();
//        test1();
        testAESGCM();
    }

    public static void test11() throws Exception {
        String key = "2020102420201024";

        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
//        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] original = cipher.doFinal("aaa\0\0\0\0\0\0\0\0\0\0\0\0\0".getBytes());
        System.out.println(new String(Base64.getEncoder().encode(original)));
    }

    public static void test1() throws Exception {
        byte[] decode = Base64.getDecoder().decode(s);
        String key = "20201024\0\0\0\0\0\0\0\0";

        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
//        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] original = cipher.doFinal(decode);
        System.out.println(new String(original));
    }

    public static void test2() throws Exception {
        byte[] decode = Base64.getDecoder().decode(s);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
//        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec("20201024".toCharArray(), "1".getBytes(), 65536, 256);

        SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
        Cipher instance = Cipher.getInstance("AES/ECB/NoPadding");
//        Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
        instance.init(Cipher.DECRYPT_MODE, secret);
        byte[] bytes = instance.doFinal(decode);
        System.out.println(new String(bytes));
    }

    public static void test3() {

    }

    public static void testAESGCM() throws Exception {

        String OUTPUT_FORMAT = "%-30s:%s";

        String pText = "Hello World AES-GCM, Welcome to Cryptography!";

        // encrypt and decrypt need the same key.
        // get AES 256 bits (32 bytes) key
        SecretKey secretKey = CryptoUtils.getAESKey(AES_KEY_BIT);

        // encrypt and decrypt need the same IV.
        // AES-GCM needs IV 96-bit (12 bytes)
        byte[] iv = CryptoUtils.getRandomNonce(IV_LENGTH_BYTE);

        byte[] encryptedText = EncryptorAesGcm.encryptWithPrefixIV(pText.getBytes(UTF_8), secretKey, iv);

        System.out.println("\n------ AES GCM Encryption ------");
        System.out.println(String.format(OUTPUT_FORMAT, "Input (plain text)", pText));
        System.out.println(String.format(OUTPUT_FORMAT, "Key (hex)", CryptoUtils.hex(secretKey.getEncoded())));
        System.out.println(String.format(OUTPUT_FORMAT, "IV  (hex)", CryptoUtils.hex(iv)));
        System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (hex) ", CryptoUtils.hex(encryptedText)));
        System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (hex) (block = 16)", CryptoUtils.hexWithBlockSize(encryptedText, 16)));

        System.out.println("\n------ AES GCM Decryption ------");
        System.out.println(String.format(OUTPUT_FORMAT, "Input (hex)", CryptoUtils.hex(encryptedText)));
        System.out.println(String.format(OUTPUT_FORMAT, "Input (hex) (block = 16)", CryptoUtils.hexWithBlockSize(encryptedText, 16)));
        System.out.println(String.format(OUTPUT_FORMAT, "Key (hex)", CryptoUtils.hex(secretKey.getEncoded())));

        String decryptedText = EncryptorAesGcm.decryptWithPrefixIV(encryptedText, secretKey);

        System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText));

    }

    public static void writeToFile(byte[] data, String file) throws IOException {
        try (FileOutputStream out = new FileOutputStream(file)) {
            IOUtils.write(data, out);
            out.flush();
        }
    }
}
